package com.gopay.scheduler.job;

import com.gopay.common.Result;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.cipher.utils.SensitiveInfoUtils;
import com.gopay.common.constants.trans.CertChannelCode;
import com.gopay.common.domain.bank.foundation.IdentityInfoMessage;
import com.gopay.common.domain.cust.CustBankAcctInfo;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.user.identify.PersCertChannelDTL;
import com.gopay.common.order.dao.CommonQueryDAO;
import com.gopay.common.portal.dao.CustBankAcctInfoQueryDAO;
import com.gopay.common.user.dao.CustPersonInfoQueryDAO;
import com.gopay.common.user.dao.PersCertChannelDtlDao;
import com.gopay.common.user.manager.PersonThreeAccountChannelManager;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.BisCertificationRemoteService;
import com.gopay.scheduler.GopayBaseJob;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.util.*;

/**
 * Created by zhaojt on 2017/4/17.
 *
 * 中诚信征信 实名认证job
 *
 */
public class ZhongChengXinZhengXinJob extends GopayBaseJob{

	
	@Resource(name = "commonQueryDAO")
    private CommonQueryDAO commonQueryDAO;

    @Autowired
    private CustPersonInfoQueryDAO custPersonInfoQueryDAO;


    @Autowired
    private PersCertChannelDtlDao persCertChannelDtlDao;


    @Resource(name = "personThreeAccountChannelManager")
    private PersonThreeAccountChannelManager personThreeAccountChannelManager;


    @Resource(name = "bisCertificationRemoteService")
    private BisCertificationRemoteService bisCertificationRemoteService;

    @Resource(name = "custBankAcctInfoQueryDAO")
    private CustBankAcctInfoQueryDAO custBankAcctInfoQueryDAO;

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    protected void doJobInternal() {

        try{
        	
        	
	        //1.查询待处理数据
	        List<PersCertChannelDTL> dtls = loadDtl();
	        
	        logger.info("loadDtl数量="+dtls.size());
	
	        //2.迭代待处理数据
	        for(PersCertChannelDTL dtl : dtls){
	        	//logger.info("custId="+dtl.getCustId()+" 开始实名认证");	        	
	        	try{
	        		CustPersonInfo custPersonInfo = custPersonInfoQueryDAO.getByCustId(dtl.getCustId());
	                if(custPersonInfo!=null){
	                	doChannelCertify(dtl, custPersonInfo);
	                }
	        	}catch(Exception e){
	            	logger.error("custId="+dtl.getCustId()+"中诚信实名异常",e);
	            }
	        }

        }catch(Exception e){
        	logger.error("中诚信实名异常",e);
        }
       
    }

    public List<PersCertChannelDTL> loadDtl(){
    	return loadDtlByCustId(null);
    }

    private List<PersCertChannelDTL> loadDtlByCustId(String custId){
    	List<PersCertChannelDTL> dtls=new ArrayList<PersCertChannelDTL>();
    	
    	StringBuilder sb = new StringBuilder();     
    	
    	Map<String, Object> map = new HashMap<String, Object>();
        
    	
    	sb.append(" select distinct t.cert_no,t.cust_id,t0.certCount from pers_cert_channel_dtl t  ");
    	sb.append(" left join ( ");
    	sb.append(" select d.cust_id,count(1) certCount  from pers_cert_channel_dtl d where d.status='01' and d.channel_code not like '4%' group by d.cust_id ");
    	sb.append(" ) t0 on t0.cust_id=t.cust_id ");
    	sb.append(" left join ( ");
    	sb.append(" select d.cert_no,d.cust_id,count(1) certCount  from pers_cert_channel_dtl d where d.status='01' and d.channel_code not like '4%' group by d.cert_no,d.cust_id  ");
    	sb.append(" having count(1)>=5 ");
    	sb.append(" ) t1 on t1.cert_no=t.cert_no ");
    	sb.append(" left join cust_person_info p on p.cust_id=t.cust_id ");
    	sb.append(" where 1=1 ");
    	sb.append(" and p.cust_name is not null and p.cert_no is not null ");
    	sb.append(" and p.cust_stat!='99' ");
    	sb.append(" and t0.certCount<5 ");
    	sb.append(" and ((t1.cert_no is not null and t0.certCount<3) or t1.cert_no is null) ");
    	
    	
    	
    	
    	if(StringUtils.isNotBlank(custId)){
    		sb.append(" and t.cust_id=:custId ");
    		map.put("custId", custId);
    	}else{
    		sb.append(" and t.created_ts>=to_date(:startDate,'yyyymmdd') ");
    		
    		Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            calendar.add(Calendar.DAY_OF_MONTH, -2);//修改时间限制条件 只认证两天内的 未认证记录 生产bug7期 lx 2017-7-24 10:32:21
            //日期T-2
            String startDate=DateUtils.format(calendar.getTime(), "yyyyMMdd");
    		
    		map.put("startDate", startDate);
    		
    		logger.info("查询开始日期startDate="+startDate);
    	}
    	
    	
    	
    	List<Object[]> rsList = commonQueryDAO.findBySql(sb.toString(), map);   
    	
    	if (rsList != null && rsList.size() > 0) {    		
    		PersCertChannelDTL dtl;
    		for (Object[] arr : rsList) {
    			dtl=new PersCertChannelDTL();
    			dtl.setCertNo((String)arr[0]);
        		dtl.setCustId((String)arr[1]);
        		
        		if(!dtl.getCertNo().contains("$")){//排除部分新生实名认证 
        			dtls.add(dtl);
        		}        		
    		}	
    	}
    	    	
        return dtls;
    }


    public void doChannelCertify(PersCertChannelDTL dtl,CustPersonInfo custPersonInfo){

        if(needcCertify(custPersonInfo.getCustId())){
            PersCertChannelDTL byCustIdAndChannel = findByCustIdAndChannel(custPersonInfo.getCustId(), CertChannelCode.ZCXZX.value);

            if(byCustIdAndChannel == null) {

                PersCertChannelDTL obj = new PersCertChannelDTL();
                obj.setCustId(custPersonInfo.getCustId());
                obj.setCertNo(custPersonInfo.getCertNo());
                obj.setChannelCode(CertChannelCode.ZCXZX.value);
                obj.setCreatedTs(new Date());
                obj.setRemark("中诚信征信实名认证");

                
                
                Result result = realNameCertify(dtl, custPersonInfo);
                if(result.isSuccess() && (Boolean) result.get("flag")){
                	logger.info("认证成功");
                    obj.setStatus("01");
                    persCertChannelDtlDao.save(obj);
                }else if(result.isSuccess() && !(Boolean) result.get("flag")){
                	logger.info("认证失败");
                    obj.setStatus("02");
                    persCertChannelDtlDao.save(obj);
                }else{
                    logger.info("调用无效!");
                }
            }
        }else{
            return ;
        }

        if(needcCertify(custPersonInfo.getCustId())){
            PersCertChannelDTL byCustIdAndChannel = findByCustIdAndChannel(custPersonInfo.getCustId(), CertChannelCode.ZCXZXM.value);

            if(byCustIdAndChannel == null) {

                PersCertChannelDTL obj = new PersCertChannelDTL();
                obj.setCustId(custPersonInfo.getCustId());
                obj.setCertNo(custPersonInfo.getCertNo());
                obj.setChannelCode(CertChannelCode.ZCXZXM.value);
                obj.setCreatedTs(new Date());
                obj.setRemark("中诚信征信手机认证");
                obj.setMobile(custPersonInfo.getCustMob());

                Result result = mobileCertify(dtl, custPersonInfo);
                if(result.isSuccess() && (Boolean) result.get("flag")){
                    logger.info("认证成功");
                    obj.setStatus("01");

                    persCertChannelDtlDao.save(obj);
                }else if(result.isSuccess() && !(Boolean) result.get("flag")){
                    logger.info("认证失败");
                    obj.setStatus("02");

                    persCertChannelDtlDao.save(obj);
                }else{
                    logger.info("调用无效!");
                }
            }
        }else{
            return ;
        }


        if(needcCertify(custPersonInfo.getCustId())){
            fourElementsCertify(dtl, custPersonInfo);
        }else{
            return ;
        }

    }

    private boolean needcCertify(String custId){
        List<PersCertChannelDTL> dtlList= loadDtlByCustId(custId);
        return dtlList!=null&&dtlList.size()>0;        
    }

    /**
     * 调bis 实名认证
     * @param dtl
     * @param custPersonInfo
     * @return
     */
    private Result realNameCertify(PersCertChannelDTL dtl,CustPersonInfo custPersonInfo){
        Result result = new Result();
        result.setSuccess(false);

        IdentityInfoMessage message = new IdentityInfoMessage();

        message.setCardHolder(custPersonInfo.getCustName());
        message.setIdentityCode(dtl.getCertNo());
        message.setChannelMak(CertChannelCode.ZCXZX.value);

        logger.info(String.format("中诚信实名认证----请求参数：custId=%s，param=%s",custPersonInfo.getCustId(), LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(message))));
        
        result = bisCertificationRemoteService.realNameCertify(message);
        
        logger.info(String.format("中诚信实名认证----响应结果：custId=%s，result=%s",custPersonInfo.getCustId(), LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(result))));
       
        return result;
    }

    /**
     * 调bis 手机认证
     * @param dtl
     * @param custPersonInfo
     * @return
     */
    private Result mobileCertify(PersCertChannelDTL dtl,CustPersonInfo custPersonInfo){
        Result result = new Result();
        result.setSuccess(false);

        IdentityInfoMessage message = new IdentityInfoMessage();

        message.setMobileNumber(custPersonInfo.getCustMob());
        message.setCardHolder(custPersonInfo.getCustName());
        message.setChannelMak(CertChannelCode.ZCXZXM.value);
        message.setIdentityCode(custPersonInfo.getCertNo());

        
        logger.info(String.format("中诚信实名手机认证----请求参数：custId=%s，param=%s",custPersonInfo.getCustId(), LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(message))));
        
        result = bisCertificationRemoteService.mobileCertify(message);
        
        logger.info(String.format("中诚信实名手机认证----响应结果：custId=%s，result=%s",custPersonInfo.getCustId(), LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(result))));


       
        return result;
    }

    /**
     * 调bis 四要素认证
     * @param dtl
     * @param custPersonInfo
     * @return
     */
    private void fourElementsCertify(PersCertChannelDTL dtl,CustPersonInfo custPersonInfo){
        IdentityInfoMessage message = new IdentityInfoMessage();

        message.setCardHolder(custPersonInfo.getCustName());
        message.setMobileNumber(custPersonInfo.getCustMob());
        message.setIdentityCode(dtl.getCertNo());
        message.setChannelMak(CertChannelCode.ZCXZXFE.value);

        List<String> cards = new ArrayList<>();

        
        List<CustBankAcctInfo> custBankAcctInfos = getCustBankAcctInfos(dtl.getCustId());

        List<PersCertChannelDTL> persCertChannelDTLs = getPersCertChannelDTL(dtl.getCustId());

        if(dtl.getCardNo() != null){
            cards.add(dtl.getCardNo());
        }

        if(custBankAcctInfos != null && custBankAcctInfos.size() > 0){
            for(CustBankAcctInfo each : custBankAcctInfos){
                if(!cards.contains(each.getBankAcctNum())){
                    cards.add(each.getBankAcctNum());
                }
            }
        }

        if(persCertChannelDTLs != null && persCertChannelDTLs.size() > 0){
            for(PersCertChannelDTL each : persCertChannelDTLs){
                String s = "";
                if(each.getChannelCode().length() == 4) {
                    s = SensitiveInfoUtils.smartDecrypt(each.getCardNo());                   
                }
                if(each.getChannelCode().length() == 4 && !cards.contains(s)){
                    cards.add(s);
                }
            }
        }

        
        Result result = new Result();
        result.setSuccess(false);


        for (String cardNo: cards) {
            PersCertChannelDTL byCustIdAndChannelAndCardNo = findByCustIdAndChannelAndCardNo(custPersonInfo.getCustId(), CertChannelCode.ZCXZXFE.value, cardNo);
            //modified by zyt ,2017-6-15，解决打印日志的时候，空指针问题
            logger.info("byCustIdAndChannelAndCardNo:{}", LoggerMaskUtils.maskString(byCustIdAndChannelAndCardNo == null ? "" : byCustIdAndChannelAndCardNo.toString()));

            if(byCustIdAndChannelAndCardNo == null) {
            	if (!needcCertify(custPersonInfo.getCustId())) {
                    break;
                }
            	
            	
                message.setBankCardNo(cardNo);

                PersCertChannelDTL obj = new PersCertChannelDTL();
                obj.setCustId(custPersonInfo.getCustId());
                obj.setCertNo(custPersonInfo.getCertNo());
                obj.setChannelCode(CertChannelCode.ZCXZXFE.value);
                obj.setCreatedTs(new Date());
                obj.setRemark("中诚信征信四要素认证");

                logger.info(String.format("中诚信实名卡号四要素认证----请求参数：custId=%s，param=%s",custPersonInfo.getCustId(), LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(message))));
                
                result = bisCertificationRemoteService.fourElementsCertify(message);
                
                logger.info(String.format("中诚信实名卡号四要素认证----响应结果：custId=%s，result=%s",custPersonInfo.getCustId(), LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(result))));


                if (result.isSuccess() && (Boolean) result.get("flag")) {
                	logger.info("认证成功");
                    obj.setCardNo(cardNo);
                    obj.setStatus("01");

                    persCertChannelDtlDao.save(obj);


                }else if(result.isSuccess() && !(Boolean) result.get("flag")){
                	logger.info("认证失败");
                    obj.setStatus("02");
                    obj.setCardNo(cardNo);

                    persCertChannelDtlDao.save(obj);
                }else{
                    logger.info("调用无效!");
                }
           

            }
        }

       
    }

    public PersCertChannelDTL findByCustIdAndChannel(String custId, String channelCode) {
        String hql="from PersCertChannelDTL p where p.custId=:custId and p.channelCode=:channelCode ";

        Map<String, Object> param = new HashMap<String, Object>();
        param.put("custId", custId);
        param.put("channelCode", channelCode);
        List<PersCertChannelDTL> list = persCertChannelDtlDao.findByHql(hql, param);
        if(null==list||list.isEmpty()){
            return null;
        }
        return list.get(0);
    }

    public PersCertChannelDTL findByCustIdAndChannelAndCardNo(String custId, String channelCode, String cardNo) {
        String hql="from PersCertChannelDTL p where p.custId=:custId and p.channelCode=:channelCode and p.cardNo in(:cardNo) ";

        Map<String, Object> param = new HashMap<String, Object>();
        param.put("custId", custId);
        param.put("channelCode", channelCode);
        param.put("cardNo", SensitiveInfoUtils.getAllHisCipherText(cardNo).toArray());

        List<PersCertChannelDTL> list = persCertChannelDtlDao.findByHql(hql, param);
        if(null==list||list.isEmpty()){
            return null;
        }
        return list.get(0);
    }

    public List<CustBankAcctInfo> getCustBankAcctInfos(String custId){

        String hql = " from CustBankAcctInfo t where t.custId = :custId and t.delFlag = '0' " ;
        HashMap<String, Object> param = new HashMap<>();
        param.put("custId", custId);

        List<CustBankAcctInfo> list = custBankAcctInfoQueryDAO.findByHql(hql, param);

        return list;
    }

    public List<PersCertChannelDTL> getPersCertChannelDTL(String custId){
        String hql = " from PersCertChannelDTL p where p.custId=:custId ";

        HashMap<String, Object> param = new HashMap<>();
        param.put("custId", custId);

        return persCertChannelDtlDao.findByHql(hql, param);
    }

    private void dealSpaceInBankCard(){
    	String hql = " from CustBankAcctInfo t  " ;
        HashMap<String, Object> param = new HashMap<>();
       
        List<CustBankAcctInfo> list = custBankAcctInfoQueryDAO.findByHql(hql, param);
    	if(list!=null&&list.size()>0){
    		int count=0;
    		for(CustBankAcctInfo card :list){
    			if(card.getBankAcctNum().contains(" ")){
    				String tmp=card.getBankAcctNum();
    				card.setBankAcctNum(card.getBankAcctNum().replace(" ", ""));
    				custBankAcctInfoQueryDAO.update(card);
    				
    				logger.info("卡号带空格替换 old="+tmp+",new="+card.getBankAcctNum());
    				count++;
    			}
    		}
    		logger.info("卡号带空格替换总记录数="+count);
    	}    	
    }
    
    

}
